package com.saas.platform.platformservicedemo.base.advice;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.alibaba.fastjson.JSON;
import com.saas.ability.core.base.exception.ParameterException;
import com.saas.ability.core.base.protocol.BaseInput;
import com.saas.ability.core.base.util.DateUtil;
import com.saas.ability.core.base.util.MethodParameterUtils;

@ControllerAdvice
public class ReqFormParamrAdvice implements HandlerMethodArgumentResolver {

	Logger logger = LoggerFactory.getLogger(ReqFormParamrAdvice.class);

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return BaseInput.class.isAssignableFrom(parameter.getParameterType());
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		try {
			BaseInput<Object> input = getBaseInput(webRequest);
			String params = webRequest.getParameter("params");
			if (!StringUtils.isEmpty(params)) {
				logger.debug("接口参数，params：{}", params);
				Class<?> clazz = MethodParameterUtils.getRequestDataType(parameter);
				Object obj = null;
				if(clazz != null && isPrimitive(clazz)){
					JSONObject jsonObject = JSON.parseObject(params);
					if (isPrimitive(clazz) && jsonObject.size() == 1) {
						Set<String> keys = jsonObject.keySet();
						for (String key : keys) {
							params = jsonObject.getString(key);
						}
						obj = conversion(clazz,params);
					}
				}else{
					try{
						Type type = ((ParameterizedType)parameter.getGenericParameterType()).getActualTypeArguments()[0];
						obj = JSON.parseObject(params, type);
					}catch(Exception e){
						logger.error("params参数不是有效的json格式,params:{}", params,e);
						throw new RuntimeException("params参数不是有效的json格式");
					}
				}
				input.setParams(obj);
			}
			return input;
		} catch (Exception e) {
			logger.error("接口参数转化发生异常", e);
			throw new ParameterException();
		}
	}

	public BaseInput<Object> getBaseInput(NativeWebRequest webRequest) {
		BaseInput<Object> baseInput = new BaseInput<>();
		baseInput.setAppId(webRequest.getParameter("appId"));
		baseInput.setCharset(webRequest.getParameter("charset"));
		baseInput.setDeviceSn(webRequest.getParameter("terminalVersion"));
		baseInput.setDeviceVersion(webRequest.getParameter("deviceVersion"));
		String timesTamp = webRequest.getParameter("timesTamp");
		if (!StringUtils.isEmpty(timesTamp)) {
			baseInput.setTimesTamp(Long.parseLong(timesTamp));
		}
		baseInput.setAccessToken(webRequest.getParameter("accessToken"));
		/*if (StringUtils.isEmpty(webRequest.getParameter("origin"))) {
			logger.error("接口请求来源不能为空");
			throw new ParameterException("接口请求来源不能为空");
		}
		baseInput.setOrigin(Integer.parseInt(webRequest.getParameter("origin")));*/

		return baseInput;
	}

	public boolean isPrimitive(Class<?> clazz) {
		return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class)
				|| clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
				|| clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
				|| clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class)
				|| clazz.isPrimitive());

	}

	public Object conversion(Class<?> clazz, String params) {
		Object obj = null;
		if (clazz.equals(Integer.class)) {
			obj = Integer.valueOf(params);
		} else if (clazz.equals(Long.class)) {
			obj = Long.valueOf(params);
		} else if (clazz.equals(Double.class)) {
			obj = Double.valueOf(params);
		} else if (clazz.equals(Float.class)) {
			obj = Float.valueOf(params);
		} else if (clazz.equals(Short.class)) {
			obj = Short.valueOf(params);
		} else if (clazz.equals(BigInteger.class)) {
			obj = new BigDecimal(params);
		} else if (clazz.equals(BigDecimal.class)) {
			obj = new BigDecimal(params);
		} else if (clazz.equals(Boolean.class)) {
			obj = Boolean.valueOf(params);
		} else if (clazz.equals(Date.class)) {
			obj = DateUtil.parseDate(params);
		} else {
			obj = params;
		}
		return obj;
	}
}
